from .op.base import Operable, OpConst

__all__ = [
    "Var",
    "Vars",
    "VarGroup",
]


class Var(Operable):
    def __init__(self, name: str = None, **args):
        if name is None:
            assert len(args) == 1
            self.name = next(iter(args.keys()))
            self.value = args[self.name]
        else:
            self.name = name
            self.value = None

    def __str__(self):
        return self.name

    def __eq__(self, other):
        if isinstance(other, Var):
            return self.name == other.name
        elif isinstance(other, str):
            return self.name == other
        else:
            return NotImplemented

    def getValue(self, valDict):
        for key, value in valDict.items():
            if self == key:
                return value
        return self if self.value is None else self.value

    def setValue(self, val):
        self.value = val
        return self

    def diff(self, dx) -> OpConst:
        return OpConst(int(self == dx))


def Vars(*names) -> "tuple[Var]":
    return tuple(map(Var, names))


def VarGroup(name, fr: int, to: int, step: int = 1) -> "tuple[Var]":
    return Vars(*(f"{name}{i}" for i in range(fr, to, step)))
